// Komentarz jednoliniowy
/* Komentarz
 * w kilku
 * liniach */


;Wyłączenie listowania kodu.
.NOLIST

;Dołączenie zewnętrznych plików
#include "m32def.inc"
.include "macros.asm"

;właczenie listowania - musi być zaznaczona
;odpowiednia opcja w projekcie
.LIST
;rozwijanie makr w pliku z listingiem
;domyślnie wyłączone
.LISTMAC

;Preprocesor znany z języka C
;Wcięcia nie są obowiązkowe (aczkolwiek zalecane) 
#define __TEST__
#ifdef __TEST__

    ;wyprowadzenie komunikatu do okna kompilacji
    .warning "__TEST__ already defined!"

#else

    .warning "__TEST__ not defined yet!"

    ;Wyświetla komunikat jaką błąd kompilacji
    #error   "Nazwa kontrolera " __PART_NAME__

#endif


;Deklaracja obszaru pamięci EEPROM
.ESEG
;ustawienie wskaźnika assemblera na podany adres
.org 0

;definicja stałych o rozmiarze bajtu (tablicy 4 stałych)
serial:     .db 0x12, 0x34,\
                0x56,\
                0x78
;definicja stałych o rozmiarze słowa (tablicy 2 stałych
wrd:        .dw 0x1234, 0x5678
    
;definicje stałych o rozmiarze bajtu
;rózne fromaty zapisu
binary:     .db 0b0101_1010     ;zapis binarny 
                                ;znak podkreślenia można umieścić pomiędzy cyframi
                                ;w celu zwiększenia czytelności - nie zmienia on wartości    
decimal:    .db 90              ;zapis dziesiętny  
octal:      .db 0132            ;zapis oktalny (ósemkowy)



;Deklaracja obszaru pamięci SRAM 
;Dane w tym obszarze pamięci nie są zainicjowane
.DSEG
tab: .BYTE 1                    ;definicja zmiennej o rozmiarze 1 bajtu 
tab2: .BYTE 16                  ;definicja tablicy o rozmiarze 16 bajtów


;Definicje stałych/symboli
.DEF tmp=R16                    ;przypisanie rejestrowi R16 aliasu
.EQU maxByte=255                ;utworzenie stałej symbolicznej


;Deklaracja obszaru pamięci kodu
;Z obszaru kodu można ładować dane do pamięci operacyjnej.
;Umożliwia to przechowywanie większej ilości stałych takich
;jak napisy itp.
.CSEG
;Ustawienie wskaźnika assemblera na komórkę pamięci
;znajdującą sie 100 słów przed końcem FLASH 
.org FLASHEND - 0x100

;utworzenie stałych o rozmiarze bajtu
bitmask:    .db 0b1010_1010, 0b0101_0101
;utworzenie stałych o rozmiarze słowa
wbitmask:   .dw 0b10101010_01010101
;utworzenie stałych o rozmiarze podwójnego słowa
dbitmask:   .dd 0x12345678
;utworzenie stałych o rozmiarze poczwórnego słowa
qbitmask:   .dq 0x12_34_56_78_9a_bc_de_f0

;Napis nie jest domyślnie zakończony zerem
;Aby zachować kompatybilność z językiem c/c++
;warto dodać znak '0' na koncu napisu.
hw:         .db "Hello World!",0

;Ustawienie wskaźnika assemblera na początek pamięci FLASH
.org 0
;ustawienie wektora przerwań
;Pod adresem NO_IRQ znajduje się najprostrza procedura obsługi przerwań 
;wykonująca jedynie rozkaz IRET (powrót z przerwania)

    rjmp    START
    rjmp    NO_IRQ  ;INT0addr   = 0x0002    ; External Interrupt Request 0
    rjmp    NO_IRQ  ;INT1addr   = 0x0004    ; External Interrupt Request 1
    rjmp    NO_IRQ  ;INT2addr   = 0x0006    ; External Interrupt Request 2
    rjmp    NO_IRQ  ;OC2addr    = 0x0008    ; Timer/Counter2 Compare Match
    rjmp    NO_IRQ  ;OVF2addr   = 0x000a    ; Timer/Counter2 Overflow
    rjmp    NO_IRQ  ;ICP1addr   = 0x000c    ; Timer/Counter1 Capture Event
    rjmp    NO_IRQ  ;OC1Aaddr   = 0x000e    ; Timer/Counter1 Compare Match A
    rjmp    NO_IRQ  ;OC1Baddr   = 0x0010    ; Timer/Counter1 Compare Match B
    rjmp    NO_IRQ  ;OVF1addr   = 0x0012    ; Timer/Counter1 Overflow
    rjmp    NO_IRQ  ;OC0addr    = 0x0014    ; Timer/Counter0 Compare Match
    rjmp    NO_IRQ  ;OVF0addr   = 0x0016    ; Timer/Counter0 Overflow
    rjmp    NO_IRQ  ;SPIaddr    = 0x0018    ; Serial Transfer Complete
    rjmp    NO_IRQ  ;URXCaddr   = 0x001a    ; USART, Rx Complete
    rjmp    NO_IRQ  ;UDREaddr   = 0x001c    ; USART Data Register Empty
    rjmp    NO_IRQ  ;UTXCaddr   = 0x001e    ; USART, Tx Complete
    rjmp    NO_IRQ  ;ADCCaddr   = 0x0020    ; ADC Conversion Complete
    rjmp    NO_IRQ  ;ERDYaddr   = 0x0022    ; EEPROM Ready
    rjmp    NO_IRQ  ;ACIaddr    = 0x0024    ; Analog Comparator
    rjmp    NO_IRQ  ;TWIaddr    = 0x0026    ; 2-wire Serial Interface
    rjmp    NO_IRQ  ;SPMRaddr   = 0x0028    ; Store Program Memory Ready

;Przesunięcie wskaźnika assemblera poza obszar 
;wektora przerwań. Nie jest to konieczne gdyż powyżej
;ustawiono procedury dla wszystkich możliwych przerwań.
;
.org INT_VECTORS_SIZE/2
START:
; Instrukcje kopiowania i transmisji danych

    LDI  r16, 100       ;wpisanie wartości do rejestru
    ;LDI R1, 100        ;tylko dla rejestrów o numerze 16 i większym
    MOV  R1, R16        ;przepisanie wartości między rejestrami (Rx <= Ry)
    MOVW R2, R0         ;przepisanie słowa pomiędzy rejestrami (Rx:Rx+1 <= Ry:Ry+1)
    ;MOVW R3, R0        ;Wartości x i y muszą być parzyste
    STS  tab, R3        ;zapisanie wartości rejestu Rx w pamięci SRAM pod dresem tab
    LDS  R0, tab        ;wczytanie wartości do rejestru ze zmiennej tab
    ;Rejestry 16-bitowe
    ;X => R26:R27
    ;Y => R28:R29
    ;Z => R30:R31
    ;Instrukcje LD można wykonywać również na rejestrach Y i Z
    LD   R4, X+         ;Wczytanie bajtu o adresie wskazanym przez zawartość rejestru X
                        ;Zwiększenie zawartości rejestru X o jeden.
    LD   R6, X          ;Wczytanie bajtu o adresie wskazanym przez X bez zmiany zawartości
    LD   R6, -X         ;Zmniejszenie o jeden zawartości rejestru X
                        ;Wczytanie bajtu o adresie wskazanym przez zawartość rejestru X
    CLR  R28            ;Ustawienie 0 w rejestrze
    LDD  R6, Y+2        ;Wczytanie bajtu o adresie wskazanym przez zawartość rejestru Y 
                        ;zwiększonego o 2 bez zmiany zawartości Y 
                        ;Podobnie dla Z (brak dla X)
    ST   Z+, R16        ;Zapis bajtu z rejestru do pamieci wskazanej przez Z
                        ;Zwiekszenie wartości Z o jeden
    ST   Z, R16         ;\
    ST   -Z, R6         ;   Analogicznie jak dla odczytu z pamięci
    STD  Z+2, R1        ;/
    
    ;Poniższa sekwencja rozkazów ładuje do rejestru Z adres qbitmask
    ;(mnożenie konieczne ze względu na dwubajtową organizację pamięci programu)
    LDI  ZL, LOW(qbitmask*2)
    LDI  ZH, HIGH(qbitmask*2)
    LPM                 ;odczyt bajtu wskazanego w Z do rejestru R0
    LPM  R1, Z+         ;odczyt i inkrementacja Z
    LPM  R1, Z          ;odczyt bez inkrementacji

    ;Zainicjowanie wskaźnika stosu
    ldi  tmp,low(RAMEND); Load low byte address of end of RAM into register R16
    out  SPL,tmp        ; Initialize stack pointer to end of internal RAM
    ldi  tmp,high(RAMEND); Load high byte address of end of RAM into register R16   
    out  SPH, tmp       ; Initialize high byte of stack pointer to end of internal RAM
                        ; out - zapis bajtu do portu
    PUSH R1             ;zapisanie zawartości rejestru na stosie (1 bajt)
    POP  R2             ;odczyt bajtu ze stosu do rejestru R2
    IN   R2, SPH        ;odczyt bajtu z portu do rejestru R2
; Instrukcje operacji na bitach

    SEC                 ; Set Carry C © 1 C 1
    CLC                 ; Clear Carry C © 0 C 1
    SEN                 ; Set Negative Flag N © 1 N 1
    CLN                 ; Clear Negative Flag N © 0 N 1
    SEZ                 ; Set Zero Flag Z © 1 Z 1
    CLZ                 ; Clear Zero Flag Z © 0 Z 1
    SEI                 ; Global Interrupt Enable I © 1 I 1
    CLI                 ; Global Interrupt Disable I © 0 I 1
    SES                 ; Set Signed Test Flag S © 1 S 1
    CLS                 ; Clear Signed Test Flag S © 0 S 1
    SEV                 ; Set Twofs Complement Overflow V © 1 V 1
    CLV                 ; Clear Twofs Complement Overflow V © 0 V 1
    SET                 ; Set T in SREG T © 1 T 1
    CLT                 ; Clear T in SREG T © 0 T 1
    SEH                 ; Set Half Carry Flag in SREG H © 1 H 1
    CLH                 ; Clear Half Carry Flag in SREG H © 0 H 1
    BSET SREG_N         ; Set flag in SREG
    BCLR SREG_N         ; Clear flag in SREG
    LDI  R16, 0xF0
    BST  R16, 4         ; Bit Store from Register to T T © Rr(b) T 1
    BLD  R16, 3         ; Bit load from T to Register Rd(b) © T None 1
    SWAP R16            ; Swap Nibbles

    ROL  R16            ; Rotate Left Through Carry 
    ROR  R16            ; Rotate Right Through Carry 
    ASR  R16            ; Arithmetic Shift Right 
    LSL  R16            ; Logical Shift Left 
    LSR  R16            ; Logical Shift Right

    SBI  PORTB, 1       ;ustawienie bitu o numerze 1 (numeracja od 0)
    CBI  PORTB, 1       ;wyzerowanie bitu o numerze 1

;Instrukcje arytmetyczne

    CLR  R0             ;wstawienie wartosci 0 do rejestru
    INC  R1             ;zwiekszenie zawartosci rejestru o 1
    DEC  R2             ;zmniejszenie zawartości rejestru o 1
    ADD  R0,  R1        ;R0 = R0 + R1
    ADC  R3,  R1        ;R3 = R3 + R1 + C   C = flaga przeniesienia
    SER  R24            ;wstawienie 0xFF do rejestru
    ADIW R24, 1         ;dodanie wartości (0-63) do rejestru 16bitowego (R24-R30)
    SUB  R3,  R1        ;R3 = R3 - R1
    SUBI R25, 1         ;R25 -= 1
    SBIW R24, 1         ;odjęcie wartości (0-63) od rejestru 16bitowego (R24-R30)
    AND  R24, R1        ;R24 = R24 & R1
    ANDI R25, 0xF       ;R25 &= 0xf
    OR   R25, R24       ;R25 = R25 | R24
    ORI  R25, 0xF0      ;R25 |= 0xf0
    EOR  R17, R16       ;R17 = R17 ^ R16
    COM  R16            ;R16 = ~R16
    NEG  R16            ;R16 = -R16
    SBR  R16, 0x0F      ;R16 = R16 | 0x0f - to samo co ORI
    CBR  R16, 0x05      ;R16 = R16 & (0xff - R16) - wyzerowanie bitów w rejestrze
    TST  R16            ;test for zero or minus
    MUL  R16, R17       ;R0:R1 = R16 * R17

; Rozkazy skoku
    jmp  skok           ;skok do etykiety 'skok' (zasięg 4 MB)
    rjmp skok           ;skok do etykiety 'skok' (zasięg 2 KB)
    ijmp                ;skok pod adresu (Z) 
    call proc           ;wywołanie procedury 'proc' (zasięg 128 KB)
    rcall proc          ;wywołanie procedury 'proc' (zasięg 2 KB)
    icall               ;wywołanie procedury spod adresu (Z)


skok:

    SBRC R16, 1         ;pomija następny rozkaz jesli bit ustawiony na 0
    NOP                 ;pusta instrukcja
    SBRS R16, 5         ;pomija następny rozkaz jesli bit ustawiony na 1
    SBIC PORTB, 1       ;pomija następny rozkaz jesli bit w porcie ustawiony na 0
    SBIS PORTB, 1       ;pomija następny rozkaz jesli bit w porcie ustawiony na 1

    ;Wywołanie makra z parametrami
    ADDW r0,r1, r2, r3
    
;procedura
proc:
    ;Ostatnim rozkazem w procedurze musi być ret
    ret

NO_IRQ:
    ;ostatnim rozkazem w procedurze przerwanie musi byc iret
    reti

;definicja makra
;parametry numerowane od 0 - @0, @1 itd.
;Makro dodające dwie liczby 16-bitowe
; rx:rx1 = rx:rx1 + ry:ry1
.MACRO ADDW;
    add @0, @2
    adc @1, @3
.ENDM
